﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TiktokAcquisition
{
    public partial class Form1 : Form
    {
        ElasticsearchClient elasticsearchClient = null;
        AcquisitionData data = null;
        Timer timer = null;
        HttpHelper httpHelper = null;
        TaskResponse response = null;
        DataTable table = new DataTable();
        Timer listenTimer = null;
        Dictionary<string, int> bloggerSourceResponse = new Dictionary<string, int>();
        public Form1()
        {
            InitializeComponent();
            InitLog();
        }
        static string ACurrentTime = string.Empty;
        private async void acquisition_Click(object sender, EventArgs e)
        {
            ACurrentTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            if (string.IsNullOrWhiteSpace(sec_uid.Text)) { MessageBox.Show("请输入sec_uid"); return; }
            this.acquisition.Enabled = false;
            stop.Enabled = true;
            data.MainSecUid = sec_uid.Text;
            if (!string.IsNullOrWhiteSpace(textBoxCount.Text))
            {
                try
                {
                    data.Count = int.Parse(textBoxCount.Text.Trim());
                }
                catch
                {

                    MessageBox.Show("请输入有效的数字!!!");
                    return;
                }
            }
            data.Gender = "";
            if (man.Checked)
            {
                data.Gender = "男 ";
            }
            if (woman.Checked)
            {
                data.Gender += "女 ";
            }
            if (Unkown.Checked)
            {
                data.Gender += "未知 ";
            }
            data.Area = "";
            if (!string.IsNullOrWhiteSpace(textBoxArea.Text))
            {
                data.Area = textBoxArea.Text.Trim();
            }
            data.Acquisitiontime = 0;
            if (!string.IsNullOrWhiteSpace(AcquisitionTime.Text))
            {
                data.Acquisitiontime = float.Parse(AcquisitionTime.Text);
            }
            string time = this.listen_time.Text;
            if (!string.IsNullOrWhiteSpace(time))
            {
                data.listenTime = (int)(double.Parse(time) * 1000);
            }
            string json = JsonConvert.SerializeObject(data);
            string taskResponse = await httpHelper.PostAsync("/fs_info", json);
            // 反序列化
            response = JsonConvert.DeserializeObject<TaskResponse>(taskResponse);
            await Log("开始采集");
            BindFanDataToGridView(await GetInfos());
            timer.Start();

        }

        private async void stop_Click(object sender, EventArgs e)
        {
            this.acquisition.Enabled = true;
            stop.Enabled = false;
            timer.Stop();
            if (!await CheckStatus())
            {
                try
                {
                    string taskResponse = await httpHelper.PostAsync($"/task/cancel/{response.TaskId}");
                    dynamic result = JsonConvert.DeserializeObject(taskResponse);
                    if (result.status.ToString() == "success")
                    {
                        await Log("已停止采集!!!");
                    }
                    else
                    {
                        await Log("停止失败，联系开发人员。");
                    }
                }
                catch
                {
                    await Log("已停止采集!!!");
                }

            }
            else
            {
                await Log("任务已结束!!!");
            }


        }

        private async void Form1_Load(object sender, EventArgs e)
        {
            await Init();

        }


        private async Task<bool> CheckStatus()
        {
            try
            {
                //检测运行状态
                string taskResponse = await httpHelper.GetAsync($"/task/status/{response.TaskId}");
                dynamic result = JsonConvert.DeserializeObject(taskResponse);
                if (result.status.ToString() == "running")
                {
                    await Log("任务运行中...");
                    return false;
                }
                else
                {
                    await Log("任务已结束...");
                    return true;
                }
            }
            catch
            {


            }
            return false;
        }
        int i = 1;
        private bool isExecuting = false; // 添加标志位，用于判断当前是否正在执行

        private async void ListenTimer_Tick(object sender, EventArgs e)
        {
            // 如果正在执行中，则直接返回，避免重入
            if (isExecuting)
            {
                await Log("上一次监听任务尚未完成，跳过本次执行");
                return;
            }

            try
            {
                isExecuting = true; // 标记为正在执行
                listenTimer.Stop(); // 先停止定时器

                string time = this.listen_time.Text;
                int listenTime = 0;
                if (!string.IsNullOrWhiteSpace(time))
                {
                    listenTime = (int)(double.Parse(time) * 1000);
                }

                string AcquisitionTime = this.AcquisitionTime.Text;
                double ATime = 0;
                if (!string.IsNullOrWhiteSpace(AcquisitionTime))
                {
                    ATime = double.Parse(AcquisitionTime);
                }

                int j = 0;
                BindLitensFanDataToGridView(await GetLitensInfos());

                var updates = new Dictionary<string, int>();
                await Log($"当前共监听{bloggerSourceResponse.Count}位博主");
                foreach (var item in bloggerSourceResponse)
                {
                    try
                    {
                        AcquisitionTime = this.AcquisitionTime.Text;
                        ATime = 0;
                        if (!string.IsNullOrWhiteSpace(AcquisitionTime))
                        {
                            ATime = double.Parse(AcquisitionTime);
                        }
                        var obj = new
                        {
                            cookies = data.Cookies[$"user{i}"],
                            main_sec_uid = item.Key,
                            total_param = item.Value,
                            aTime = ATime
                        };
                        string json = JsonConvert.SerializeObject(obj);
                        var jsondata = JsonConvert.DeserializeObject<BloggersResponse>(
                            await httpHelper.PostAsync($"/liten_bloggers", json));
                        updates[item.Key] = jsondata.total;

                        if (data.Cookies.Count == i)
                        {
                            i = 0;
                        }
                        i++;
                        j++;

                        time = this.listen_time.Text;
                        listenTime = 0;
                        if (!string.IsNullOrWhiteSpace(time))
                        {
                            listenTime = (int)(double.Parse(time) * 1000);
                        }
                        if (!string.IsNullOrWhiteSpace(time))
                        {
                            await Task.Delay(listenTime);
                        }
                        await Log($"当前正在监听第{j}位博主");
                    }
                    catch (Exception ex)
                    {

                        await LogService.Instance.WriteErrorLog($"发生未处理的异常：{ex?.ToString()} 博主{item.Key}监听异常！！！");
                    }

                }

                foreach (var update in updates)
                {
                    bloggerSourceResponse[update.Key] = update.Value;
                }
            }
            catch (Exception ex)
            {
                await LogService.Instance.WriteErrorLog($"发生未处理的异常：{ex?.ToString()}");
            }
            finally
            {
                isExecuting = false; // 重置执行标志
                listenTimer.Start(); // 重新启动定时器
            }
        }
        private async void Timer_Tick(object sender, EventArgs e)
        {
            try
            {
                // 停止定时器以防重入
                timer.Stop();

                // 执行你的方法
                var infos = await GetInfos();
                BindFanDataToGridView(infos);



            }
            catch (Exception ex)
            {
                // 处理异常
                //MessageBox.Show($"发生错误: {ex.Message}");
                await LogService.Instance.WriteErrorLog($"发生未处理的异常：{ex?.ToString()}");
            }
            finally
            {
                // 重新启动定时器
                timer.Start();
            }

            try
            {
                if (await CheckStatus())
                {
                    acquisition.Enabled = true;
                    timer.Stop();
                }
            }
            catch
            {
            }
        }
        private async Task Init()
        {

            // 创建定时器
            timer = new Timer();
            timer.Interval = 3000; // 3秒 = 3000毫秒
            timer.Tick += Timer_Tick;

            // 创建定时器
            listenTimer = new Timer();
            listenTimer.Interval = 10000; // 3秒 = 3000毫秒
            listenTimer.Tick += ListenTimer_Tick;
            this.label_count.Text = "";
            this.listensCount.Text = "";



            string filePath = "acquisition.json";

            try
            {
                // 2. 读取文件内容
                string jsonContent = File.ReadAllText(filePath);
                // 3. 反序列化为对象
                data = JsonConvert.DeserializeObject<AcquisitionData>(jsonContent);
                elasticsearchClient = new ElasticsearchClient(data.ES.Host);
                httpHelper = new HttpHelper(data.AcquisitionApi);
            }
            catch (Exception ex)
            {
                //MessageBox.Show($"加载失败: {ex.Message}");
                await LogService.Instance.WriteErrorLog($"发生未处理的异常：{ex?.ToString()}");
            }



        }



        private async Task<List<FanDetail>> GetInfos()
        {
            var query = new
            {
                size = 10000,
                _source = new[] { "fan_id" },
                query = new
                {
                    @bool = new
                    {
                        must = new object[]
                    {
                        new
                        {
                            term = new Dictionary<string, object>
                            {
                                ["blogger_id"] = this.sec_uid.Text
                            }
                        },
                        new
                        {
                            range = new Dictionary<string, object>
                            {
                                ["first_crawl_time"] = new
                                {
                                    gt = ACurrentTime // 使用当前本地时间
                                }
                            }
                        }
                    }
                    }
                },
                sort = new[]
                        {
                            new Dictionary<string, string>
                            {
                                { "first_crawl_time", "desc" }
                            }
                        }
            };
            var relationResponse = await elasticsearchClient.SearchAsync<BloggerFanRelation>(data.ES.BloggerFansRelation, query);
            // 提取所有粉丝ID（去重处理）
            var fanIds = relationResponse.Hits.Items
                .Select(h => h.Source.FanId)
                .Distinct()
                .ToList();

            if (!fanIds.Any())
            {
                await Log("没有找到粉丝数据");
                return null;
            }



            // 第二步：批量获取粉丝详细信息
            var mgetResponse = await elasticsearchClient.MultiGetFanDetailsAsync<FanDetail>(data.ES.FansIndex, fanIds);

            if (mgetResponse.Docs == null || !mgetResponse.Docs.Any(d => d.Found))
            {
                await Log("没有获取到粉丝详细信息");
                return null;
            }

            // 处理获取到的粉丝详细信息
            var fanDetails = mgetResponse.Docs
                .Where(d => d.Found)
                .Select(d => d.Source)
                .ToList();

            await Log($"成功获取到 {fanDetails.Count} 条粉丝详细信息");


            return fanDetails.ToList();
        }

        static string currentTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        private async Task<List<FanDetail>> GetLitensInfos()
        {
            var query = new
            {
                size = 10000, // 返回结果数量
                _source = new[] { "fan_id" }, // 指定返回字段
                query = new
                {
                    @bool = new
                    {
                        must = new object[]
                {
                    new
                    {
                        term = new Dictionary<string, object>
                        {
                            ["status"] = "0"
                        }
                    },
                    new
                    {
                        term = new Dictionary<string, object>
                        {
                            ["is_in_monitor_list"] = true
                        }
                    },
                    new
                    {
                        range = new Dictionary<string, object>
                        {
                            ["first_crawl_time"] = new
                            {
                                gt = currentTime // 大于当前时间
                            }
                        }
                    }
                }
                    }
                },
                sort = new[]
                {
                    new Dictionary<string, string>
                    {
                        { "first_crawl_time", "desc" }
                    }
                } as object // 避免匿名类型转换问题
            };
            var relationResponse = await elasticsearchClient.SearchAsync<BloggerFanRelation>(data.ES.FansIndex, query);
            // 提取所有粉丝ID（去重处理）
            var fanIds = relationResponse.Hits.Items
                .Select(h => h.Source.FanId)
                .Distinct()
                .ToList();

            if (!fanIds.Any())
            {
                await Log("没有找到粉丝数据");
                return null;
            }



            // 第二步：批量获取粉丝详细信息
            var mgetResponse = await elasticsearchClient.MultiGetFanDetailsAsync<FanDetail>(data.ES.FansIndex, fanIds);

            if (mgetResponse.Docs == null || !mgetResponse.Docs.Any(d => d.Found))
            {
                await Log("没有获取到粉丝详细信息");
                return null;
            }

            // 处理获取到的粉丝详细信息
            var fanDetails = mgetResponse.Docs
                .Where(d => d.Found)
                .Select(d => d.Source)
                .ToList();

            await Log($"成功获取到 {fanDetails.Count} 条监听粉丝详细信息");


            return fanDetails.ToList();
        }

        int count = 0;
        private void BindFanDataToGridView(List<FanDetail> fanDetails)
        {
            if (fanDetails == null) return;
            if (fanDetails.Count == count) return;
            // 直接绑定 List<FanDetail>（自动生成列）
            dataGridInfos.DataSource = fanDetails;

            int totalWidth = dataGridInfos.Width - (dataGridInfos.RowHeadersVisible ? dataGridInfos.RowHeadersWidth : 0);

            dataGridInfos.Columns["FanId"].Width = (int)(totalWidth * 0.20);    // 15%
            dataGridInfos.Columns["Nickname"].Width = (int)(totalWidth * 0.20); // 20%
            dataGridInfos.Columns["Gender"].Width = (int)(totalWidth * 0.08);  // 10%
            dataGridInfos.Columns["Region"].Width = (int)(totalWidth * 0.08);   // 15%
            dataGridInfos.Columns["AvatarUrl"].Width = (int)(totalWidth * 0.22);// 20%
            dataGridInfos.Columns["FirstCrawlTime"].Width = (int)(totalWidth * 0.20);// 20%


            // 可选：自定义列名（如果不想用属性名）
            dataGridInfos.Columns["FanId"].HeaderText = "粉丝ID";
            dataGridInfos.Columns["Nickname"].HeaderText = "昵称";
            dataGridInfos.Columns["Gender"].HeaderText = "性别";
            dataGridInfos.Columns["Region"].HeaderText = "地区";
            dataGridInfos.Columns["AvatarUrl"].HeaderText = "头像URL";
            dataGridInfos.Columns["FirstCrawlTime"].HeaderText = "首次抓取时间";



            // 然后隐藏所有列
            foreach (DataGridViewColumn column in dataGridInfos.Columns)
            {
                column.Visible = false;
            }

            // 只显示你需要的列
            dataGridInfos.Columns["FanId"].Visible = true;
            dataGridInfos.Columns["Nickname"].Visible = true;
            dataGridInfos.Columns["Gender"].Visible = true;
            dataGridInfos.Columns["Region"].Visible = true;
            dataGridInfos.Columns["AvatarUrl"].Visible = true;
            dataGridInfos.Columns["FirstCrawlTime"].Visible = true;




            // 设置头像列为超链接样式（可选）
            if (dataGridInfos.Columns.Contains("AvatarUrl"))
            {
                dataGridInfos.Columns["AvatarUrl"].DefaultCellStyle.ForeColor = Color.Blue;
                dataGridInfos.Columns["AvatarUrl"].DefaultCellStyle.Font =
                    new Font(dataGridInfos.Font, FontStyle.Underline);
            }

            label_count.Text = $"当前页共{fanDetails.Count}条数据";
        }

        private void BindLitensFanDataToGridView(List<FanDetail> fanDetails)
        {
            if (fanDetails == null) return;
            if (fanDetails.Count == count) return;
            // 直接绑定 List<FanDetail>（自动生成列）
            dataGridLstenInfos.DataSource = fanDetails;

            int totalWidth = dataGridLstenInfos.Width - (dataGridLstenInfos.RowHeadersVisible ? dataGridLstenInfos.RowHeadersWidth : 0);

            dataGridLstenInfos.Columns["FanId"].Width = (int)(totalWidth * 0.20);    // 15%
            dataGridLstenInfos.Columns["Nickname"].Width = (int)(totalWidth * 0.20); // 20%
            dataGridLstenInfos.Columns["Gender"].Width = (int)(totalWidth * 0.08);  // 10%
            dataGridLstenInfos.Columns["Region"].Width = (int)(totalWidth * 0.08);   // 15%
            dataGridLstenInfos.Columns["AvatarUrl"].Width = (int)(totalWidth * 0.22);// 20%
            dataGridLstenInfos.Columns["FirstCrawlTime"].Width = (int)(totalWidth * 0.20);// 20%


            // 可选：自定义列名（如果不想用属性名）
            dataGridLstenInfos.Columns["FanId"].HeaderText = "粉丝ID";
            dataGridLstenInfos.Columns["Nickname"].HeaderText = "昵称";
            dataGridLstenInfos.Columns["Gender"].HeaderText = "性别";
            dataGridLstenInfos.Columns["Region"].HeaderText = "地区";
            dataGridLstenInfos.Columns["AvatarUrl"].HeaderText = "头像URL";
            dataGridLstenInfos.Columns["FirstCrawlTime"].HeaderText = "首次抓取时间";



            // 然后隐藏所有列
            foreach (DataGridViewColumn column in dataGridLstenInfos.Columns)
            {
                column.Visible = false;
            }

            // 只显示你需要的列
            dataGridLstenInfos.Columns["FanId"].Visible = true;
            dataGridLstenInfos.Columns["Nickname"].Visible = true;
            dataGridLstenInfos.Columns["Gender"].Visible = true;
            dataGridLstenInfos.Columns["Region"].Visible = true;
            dataGridLstenInfos.Columns["AvatarUrl"].Visible = true;
            dataGridLstenInfos.Columns["FirstCrawlTime"].Visible = true;




            // 设置头像列为超链接样式（可选）
            if (dataGridLstenInfos.Columns.Contains("AvatarUrl"))
            {
                dataGridLstenInfos.Columns["AvatarUrl"].DefaultCellStyle.ForeColor = Color.Blue;
                dataGridLstenInfos.Columns["AvatarUrl"].DefaultCellStyle.Font =
                    new Font(dataGridLstenInfos.Font, FontStyle.Underline);
            }

            listensCount.Text = $"当前页共获取{fanDetails.Count}条最新监听数据";
        }

        private async void listen_Click(object sender, EventArgs e)
        {
            listen.Enabled = false;
            stoplisten.Enabled = true;
            currentTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            try
            {

                var query = new
                {
                    query = new
                    {
                        term = new
                        {
                            is_listening = true
                        }
                    },
                    _source = new[] { "blogger_id" }, // 使用数组表示字段列表
                    size = 10000 // 设置足够大的值（Elasticsearch 默认单次最多返回 10000 条）
                };
                var Response = await elasticsearchClient.SearchAsync<BloggerSource>(data.ES.Blogger_listening, query);
                int sNumber = 0;
                int eNUMBER = 0;
                if (!string.IsNullOrWhiteSpace(stratNumber.Text))
                {
                    sNumber = int.Parse(stratNumber.Text);
                }
                if (!string.IsNullOrWhiteSpace(endNumber.Text))
                {
                    eNUMBER = int.Parse(endNumber.Text);
                }
                int i = 0;
                if (sNumber == 0)
                {
                    MessageBox.Show("您没有填写监听列表的起始和结束位置，将监听所有！");
                }
                foreach (var item in Response.Hits.Items)
                {
                    i++;
                    if (sNumber > 0 && eNUMBER > 0 && i >= sNumber && i <= eNUMBER)
                    {
                        if (!bloggerSourceResponse.ContainsKey(item.Id))
                        {
                            bloggerSourceResponse.Add(item.Id, 0);
                        }
                    }
                    else if (sNumber == 0)
                    {
                        if (!bloggerSourceResponse.ContainsKey(item.Id))
                        {
                            bloggerSourceResponse.Add(item.Id, 0);
                        }
                    }
                }
                await Log($"获取监听列表完成,当前共监听{Response.Hits.Items.Count}位博主");
                listenTimer.Start();
            }
            catch (Exception ex)
            {

                throw new Exception(ex.ToString());
            }

        }



        #region 日志

        private void InitLog()
        {
            // 设置一些初始属性
            richTextBoxLogs.ReadOnly = true;
            richTextBoxLogs.ScrollBars = RichTextBoxScrollBars.Vertical;
            richTextBoxLogs.WordWrap = true;
            richTextBoxLogs.Font = new System.Drawing.Font("Consolas", 10);
        }
        public async Task Log(string message, Color color = default)
        {
            if (color == default)
            {
                color = SystemColors.WindowText; // 默认颜色
            }

            if (richTextBoxLogs.InvokeRequired)
            {
                richTextBoxLogs.Invoke((Action)(async () =>
                {
                    await AppendTextWithColor(message + "." + Environment.NewLine, color);
                }));

            }
            else
            {
                await AppendTextWithColor(message + "." + Environment.NewLine, color);
            }


            // 滚动到底部
            richTextBoxLogs.ScrollToCaret();
        }

        private async Task AppendTextWithColor(string text, Color color)
        {
            if (color == Color.Red)
            {
                await LogService.Instance.WriteErrorLog(text);
            }
            else
            {
                await LogService.Instance.WriteInfoLog(text);
            }
            // 保存当前选择位置
            int start = richTextBoxLogs.TextLength;
            richTextBoxLogs.AppendText($"{DateTime.Now} {text}");
            int end = richTextBoxLogs.TextLength;

            // 设置选中的文本颜色
            richTextBoxLogs.Select(start, end - start);
            richTextBoxLogs.SelectionColor = color;
            richTextBoxLogs.SelectionLength = 0; // 取消选中
        }
        #endregion

        private async void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                await httpHelper.GetAsync($"/tasks/cancel_all");
            }
            catch
            {
            }
        }

        private void stoplisten_Click(object sender, EventArgs e)
        {
            listen.Enabled = true;
            stoplisten.Enabled = false;
            listenTimer.Stop();

        }
        // 弹出文件选择对话框并返回路径
        static string SelectFile()
        {
            var openFileDialog = new OpenFileDialog
            {
                Title = "选择文本文件",
                Filter = "文本文件|*.txt|所有文件|*.*",
                InitialDirectory = AppDomain.CurrentDomain.BaseDirectory // 默认打开程序所在目录
            };

            return openFileDialog.ShowDialog() == DialogResult.OK
                ? openFileDialog.FileName
                : null;
        }
        private async void buttonBatch_Click(object sender, EventArgs e)
        {
            // 1. 让用户选择文件
            string filePath = SelectFile();

            if (string.IsNullOrEmpty(filePath))
            {
                Console.WriteLine("用户取消了选择。");
                return;
            }

            // 2. 读取并遍历文件内容
            string prefixToRemove = "https://www.douyin.com/user/";
            try
            {
                string[] lines = File.ReadAllLines(filePath);
                foreach (string line in lines)
                {
                    // 检查是否以前缀开头，然后截取后面的部分
                    if (line.StartsWith(prefixToRemove))
                    {
                        string extractedPart = line.Substring(prefixToRemove.Length);
                        // 定义文档内容
                        var bloggerDocument = new
                        {
                            blogger_id = extractedPart,
                            is_listening = true
                        };

                        await elasticsearchClient.IndexDocumentAsync(data.ES.Blogger_listening, extractedPart, bloggerDocument);
                        await Log($"ID为：{extractedPart} 的博主已被监听!!!");
                    }
                    else
                    {
                        Console.WriteLine("此行格式不符合预期: " + line);
                    }
                }
                await Log($"导入完成!!!");
            }
            catch (Exception ex)
            {
                Console.WriteLine("发生错误: " + ex.Message);
            }
        }

        private async void restrat_Click(object sender, EventArgs e)
        {
            try
            {
                HttpHelper httpHelper = new HttpHelper("http://154.19.84.80:8899");
                await httpHelper.GetAsync("/restart_program");
                MessageBox.Show("已重启！");
            }
            catch
            {


            }

        }
    }

    public class BloggersResponse
    {
        public string status { get; set; }
        public string message { get; set; }
        public int total { get; set; }  // 确保类型与API返回一致
    }
}
